#include <stdio.h>
#include <stdarg.h>
 
/**
 * @brief 自定义错误输出函数
 * 
 * 该函数用于输出格式化的错误信息，包括错误代码、文件名、函数名、行号以及用户自定义的错误信息。
 * 所有信息均输出到标准错误流 stderr。
 * 
 * @param code    错误代码，用于标识错误的类型或级别。
 * @param file    发生错误的文件名，通常由预处理器宏 __FILE__ 提供。
 * @param func    发生错误的函数名，通常由预处理器宏 __FUNCTION__ 提供。
 * @param line    发生错误的行号，通常由预处理器宏 __LINE__ 提供。
 * @param format  格式化字符串，用于输出用户自定义的错误信息，支持类似于 printf 的格式化占位符。
 * @param ...     可变数量的参数，根据 format 提供的格式化占位符进行匹配。
 */
void errout(int code, char *file, const char *func, int line, char *format, ...) {
    // 定义一个 va_list 类型的变量，用于存储可变参数列表的信息。
    va_list args;
    
    // 初始化 args，使其指向 format 之后的第一个参数。
    va_start(args, format);
    
    // 输出文件名、函数名和行号到标准错误流 stderr。
    // 使用 | 作为分隔符，方便阅读。
    fprintf(stderr, "file:%s| func:%s| line:%d|", file, func, line);
    
    // 使用 vfprintf 函数，根据 format 提供的格式化字符串和 args 中的可变参数，
    // 将用户自定义的错误信息输出到标准错误流 stderr。
    vfprintf(stderr, format, args);
    
    // 输出换行符，确保每条错误信息独占一行。
    fprintf(stderr, "\n");
    
    // 清理 va_list 变量，释放其占用的资源。
    va_end(args);
    
    // 注意：虽然函数接收了一个 error code 参数，但当前实现中并未使用该参数。
    // 如果需要，可以在输出信息中包含错误代码，例如：fprintf(stderr, "Error code:%d ", code);
}
int main() {
    // 示例调用 errout 函数
    errout(1, __FILE__, __FUNCTION__, __LINE__, "Failed to open file %s with error %s", "example.txt", "permission denied");
    errout(1, __FILE__, __FUNCTION__, __LINE__, "database not connect");
    printf("Hello, World!\n");
    return 0;
}